package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;

import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ResourceServiceImpl implements ResourceService {
    @Autowired
    private ResourceMapper resourceMapper;

    @Override
    @Cacheable(value = CacheConstant.RESOURCE_LIST ,key ="#resourceDto.hashCode()")
    public List<ResourceVo> list(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        List<ResourceVo> list = resourceMapper.list(resource);
        return list;
    }

    @Override
    @Cacheable(value = CacheConstant.RESOURCE_TREE )
    public TreeVo resourceTreeVo(ResourceDto resourceDto) {
        //1.创建返回数据的对象
        TreeVo treeVo = new TreeVo();

        //2.创建根节点 并构建目录关系
        TreeItemVo root= new TreeItemVo();
        root.setId(SuperConstant.ROOT_PARENT_ID);
        root.setLabel("智慧养老院");
        //声明一个ArrayList并封装根节点
        List<TreeItemVo> list = new ArrayList<>();
        list.add(root);
        //把根节点封装到TreeVo
        treeVo.setItems(list);

        //3.通过条件查询所有的菜单节点
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        resource.setParentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID));
        resource.setDataState(SuperConstant.DATA_STATE_0);
        resource.setResourceType(SuperConstant.MENU);
        List<ResourceVo> resourceVoList = resourceMapper.list(resource);

        //4.遍历所有查找到的节点 将符合条件的用ArrayList封装
//        List<ResourceVo> firstTree =new ArrayList<>();
//        for (ResourceVo r : resourceVoList) {
//            if (r.getParentResourceNo().equals(root.getId())){
//                firstTree.add(r);
//            }
//        }
        //找到符合条件的资源并且封装到firstTree数组里 从父目录中过滤出所有的符合条件的子目录
        List<ResourceVo> firstTree = resourceVoList.stream().filter(resourceVo -> {
            if (resourceVo.getParentResourceNo().equals(root.getId())) {
                return true;
            } else {
                return false;
            }
        }).collect(Collectors.toList());


        //把ResourceVo数组转换成TreeItemVo数组
        List<TreeItemVo> firstTreeList = firstTree.stream().map(resourceVo -> {
            TreeItemVo treeItemVo = new TreeItemVo();
            treeItemVo.setId(resourceVo.getResourceNo());
            treeItemVo.setLabel(resourceVo.getResourceName());
            return treeItemVo;
        }).collect(Collectors.toList());

        //将一级目录封装到根目录
        root.setChildren(firstTreeList);


        //遍历每一个一个目录 然后找对应的一级目录下的二级目录 并构造关系
        root.getChildren().stream().map(first ->{
            List<ResourceVo> secondTree = resourceVoList.stream().filter(r -> {
                if (r.getParentResourceNo().equals(first.getId())) {
                    return true;
                } else {
                    return false;
                }
            }).collect(Collectors.toList());

            List<TreeItemVo> secondTreeList = secondTree.stream().map(r -> {
                TreeItemVo vo = new TreeItemVo();
                vo.setId(r.getResourceNo());
                vo.setLabel(r.getResourceName());
                return vo;
            }).collect(Collectors.toList());
            first.setChildren(secondTreeList);

            return first;
        }).collect(Collectors.toList());

        //遍历每一个二级目录 然后找到对应二级目录下的三级目录 并构造关系
        root.getChildren().stream().map(first ->{
            first.getChildren().stream().map(second -> {
                List<ResourceVo> thirdTree = resourceVoList.stream().filter(r -> {
                    if (r.getParentResourceNo().equals(second.getId())) {
                        return true;
                    } else {
                        return false;
                    }
                }).collect(Collectors.toList());

                List<TreeItemVo> thirdTreeList = thirdTree.stream().map(third -> {
                    TreeItemVo vo = new TreeItemVo();
                    vo.setId(third.getResourceNo());
                    vo.setLabel(third.getResourceName());
                    return vo;
                }).collect(Collectors.toList());

                second.setChildren(thirdTreeList);
                return second;
            }).collect(Collectors.toList());

            return first;
        }).collect(Collectors.toList());

        return treeVo;
    }

    /**
     * 新增资源
     * @param resourceDto
     */
    @Override
    @Caching(evict = {@CacheEvict(value = CacheConstant.RESOURCE_LIST ,allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE ,allEntries = true)})
    public void createResource(ResourceDto resourceDto) {
        //属性拷贝 请求参数中不携带resourceNo 只能获取parentResourceNo 新增的resourceNo 需要手动生成
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        String parentResourceNo = resource.getParentResourceNo();

        //查询父资源 根据父资源ResourceNo去查找具体的父resource
        Resource parentResource = resourceMapper.selectByResourceNo(parentResourceNo);
        //将父资源和新增过后的子资源状态设置为一致的
        resource.setDataState(parentResource.getDataState());

        //该resource是否是按钮 是true 则代表该resource为按钮，则不限制层级否则为menu
        boolean flag = resource.getResourceType().equals(SuperConstant.BUTTON);


        //调用createResourceNo 传入父亲parentResourceNo和是否为按钮
        resource.setResourceNo(createResourceNo(parentResourceNo, flag));

        resource.setCreateTime(LocalDateTime.now());
        resource.setCreateBy(1L);
        resourceMapper.insert(resource);
    }

    /**
     * 创建资源的编号
     * @param parentResourceNo
     * @return
     */
    private String createResourceNo(String parentResourceNo,boolean isIgnore) {

        //判断资源编号是否大于三级
        //100 001 000 000 000
        //100 001 001 000 000
        //100 001 001 001 000
        //100 001 001 001 001 001
        if (isIgnore && NoProcessing.processString(parentResourceNo).length() / 3 >= 5) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }

        //根据父资源编号查询子资源
        Resource resource = Resource.builder().parentResourceNo(parentResourceNo).build();
        List<ResourceVo> resources = resourceMapper.list(resource);
        if (EmptyUtil.isNullOrEmpty(resources)) {
            //无下属节点，创建新的节点编号  100 001 001 001 000--->100 001 001 001 001
            return NoProcessing.createNo(parentResourceNo, false);
        } else {
            //有下属节点，在已有的节点上追加
            //先获取已有节点的最大值--100001003000000
            Long maxNo = resources.stream().map(r -> {
                return Long.valueOf(r.getResourceNo());
            }).max(Comparator.comparing(i -> i)).get();

            return NoProcessing.createNo(String.valueOf(maxNo), true);
        }
    }

    /**
     * 启用或者禁用
     * @param resourceDto
     */
    @Transactional
    @Override
    public Boolean enableResource(ResourceDto resourceDto) {
        //resource作为查询参数
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        //该资源设置status = 1 禁用 并且把该资源下的子资源状态也同步修改（存在的话）
        String dataState = resourceDto.getDataState();

        resource.setDataState(dataState);
        resourceMapper.update(resource);
        //根据该资源的ResourceNo去找该资源下的子资源
        List<Resource> list =  resourceMapper.getResourceNoByParent(NoProcessing.processString(resourceDto.getResourceNo()));

        //遍历所有的子资源 状态和父资源保持一致
        list.stream().map(resourceVo -> {
            resourceVo.setDataState(dataState);
            resourceVo.setUpdateTime(LocalDateTime.now());
            resourceVo.setUpdateBy(1L);

            resourceMapper.update(resourceVo);
            return resourceVo;
        }).collect(Collectors.toList());

        return true;
    }

    /**
     * 修改
     * @param resourceDto
     */
    @Override
    public void update(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        //这个是修改后的parentN0 如何取？在Dto中直接获取新的父资源的
        String s = NoProcessing.processString(resourceDto.getParentResourceNo());
        //这个是修改前的parentN0 如何取？在resourceMapper中根据ResourceNo()查找到的
        Resource orginResource = resourceMapper.selectByResourceNo(resourceDto.getResourceNo());
        String s1 = NoProcessing.processString(orginResource.getParentResourceNo());

        //s1修改前的长度如果比现在的大 说明是提层级
        Integer flag =  s1.length() - s.length();
        //生成新的resourceNo
        createResourceNo(resourceDto.getResourceNo(), true);

        //根据dto的原有资源 如果是一级 同样会出拿出2，3，4，5
        //children对应是所有的子资源
        List<Resource> children = resourceMapper.selectByParentResourceNo(NoProcessing.processString(resourceDto.getResourceNo()));

//        父100001 001 002 000 000  子100001 001 002 001 000
//  修改后 父100001 002 000 000 000  子100001 001 003 000 000
//        100001

        children.stream().map(r->{
            //判断层级变化是降还是升
            if(flag >0){
                //如果是提升 则。。。
            }else{
                //如果是 则。。。
            }
        return r;
        }).collect(Collectors.toList());
    }

    /**
     * 动态菜单
     * @return
     */
    @Override
    public List<MenuVo> menus() {
        //1. 根据ThreadLocal查询当前登录的用户
        Long userId = UserThreadLocal.get();

        //2. 通过用户id查询用户的所有的菜单
        List<MenuVo> menuVoList = resourceMapper.selectMenuByUserId(userId);

        //3. 根据菜单的父no进行分组统计
        Map<String, List<MenuVo>> parentMap = menuVoList.stream().collect(Collectors.groupingBy(MenuVo::getParentResourceNo));

        //4. 遍历每一个菜单 用自己的resourceno到统计结果中查询数据 如果有子菜单 则设置关系
        menuVoList.forEach(menuVo -> {
            //构建redirect 和meta
            menuVo.setRedirect("/" + menuVo.getName());
            MenuMetaVo menuMetaVo = new MenuMetaVo();
            menuMetaVo.setTitle(menuVo.getName());
            menuVo.setMeta(menuMetaVo);
//            String path = menuVo.getPath();

            List<MenuVo> subList = parentMap.get(menuVo.getResourceNo());
            if(!EmptyUtil.isNullOrEmpty(subList)){
//                subList.forEach(m->{
//                    m.setPath(path.charAt(0)=='/'? path:("/"+path)+"/"+ m.getPath());
//                });
                menuVo.setChildren(subList);
            }
        });

        //5. 获取根菜单的所有子菜单并返回
        return parentMap.get(SuperConstant.ROOT_PARENT_ID);
    }
}
